/**
 * Copyright (C) 2016 Robinhood Markets, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.jinatonic.confetti;

import com.github.jinatonic.confetti.confetto.Confetto;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.ComponentParent;
import ohos.agp.render.Canvas;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

import java.util.List;

/**
 * A helper temporary view that helps render the confetti. This view will attach itself to the
 * view root, perform the animation, and then once all of the confetti has completed its animation,
 * it will automatically remove itself from the parent.
 */
public class ConfettiView extends Component implements Component.LayoutRefreshedListener {
    private List<Confetto> confetti;
    private boolean terminated;

    private boolean touchEnabled;
    private Confetto draggedConfetto;

    public static ConfettiView newInstance(Context context) {
        final ConfettiView confettiView = new ConfettiView(context, null);
        ComponentContainer.LayoutConfig layoutConfig =
                new ComponentContainer.LayoutConfig(
                        ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);

        confettiView.setLayoutConfig(layoutConfig);

        return confettiView;
    }

    public ConfettiView(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    public ConfettiView(Context context, AttrSet attrSet, String style) {
        super(context, attrSet, style);

        addDrawTask(
                new DrawTask() {
                    @Override
                    public void onDraw(Component component, Canvas canvas) {
                        onDrawComponent(canvas);
                    }
                });

        setTouchEventListener(
                new TouchEventListener() {
                    @Override
                    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                        return onTouch(touchEvent);
                    }
                });

        setLayoutRefreshedListener(this);
    }

    /**
     * Sets the list of confetti to be animated by this view.
     *
     * @param confetti the list of confetti to be animated.
     */
    public void bind(List<Confetto> confetti) {
        this.confetti = confetti;
    }

    /**
     * Enables or disables touch events for the confetti generated by this manager.
     * @see ConfettiManager#setTouchEnabled(boolean)
     *
     * @param touchEnabled whether or not to enable touch
     */
    public void setTouchEnabled(boolean touchEnabled) {
        this.touchEnabled = touchEnabled;
    }

    /**
     * Terminate the current running animation (if any) and remove this view from the parent.
     */
    public void terminate() {

        if (!terminated) {
            this.terminated = true;
//            if (getComponentParent() != null) {
//                getComponentParent().postLayout();
//            }
            final ComponentParent parent = getComponentParent();
            if (parent != null && parent instanceof ComponentContainer) {
                setVisibility(HIDE);
                final ComponentContainer vg = (ComponentContainer) parent;
                vg.removeComponent(ConfettiView.this);
                vg.invalidate();
            }
        }
    }

    /**
     * Reset the internal state of this view to allow for a new confetti animation.
     */
    public void reset() {
        this.terminated = false;
    }

    @Override
    public void onRefreshed(Component component) {
//        System.out.println("ConfettiView onRefreshed() = " + terminated);

//        if (terminated) {
//            final ComponentParent parent = getComponentParent();
//            if (parent != null && parent instanceof ComponentContainer) {
//                final ComponentContainer vg = (ComponentContainer) parent;
//                vg.removeComponent(ConfettiView.this);
//                vg.invalidate();
//            }
//        }
    }

    private void onDrawComponent(Canvas canvas) {
//        System.out.println("ConfettiView onDrawComponent() = " + terminated);
        if (!terminated) {
            canvas.save();
            for (Confetto confetto : this.confetti) {
                confetto.draw(canvas);
            }
            canvas.restore();
        }
    }

    private boolean onTouch(TouchEvent event) {
        boolean handled = false;
        if (touchEnabled) {
            switch (event.getAction()) {
                case TouchEvent.PRIMARY_POINT_DOWN:
                    for (Confetto confetto : confetti) {
                        if (confetto.onTouchDown(event,ConfettiView.this)) {
                            draggedConfetto = confetto;
                            handled = true;
                            break;
                        }
                    }
                    break;
                case TouchEvent.POINT_MOVE:
                    if (draggedConfetto != null) {
                        draggedConfetto.onTouchMove(event,ConfettiView.this);
                        handled = true;
                    }
                    break;
                case TouchEvent.PRIMARY_POINT_UP:
                case TouchEvent.CANCEL:
                    if (draggedConfetto != null) {
                        draggedConfetto.onTouchUp(event,ConfettiView.this);
                        draggedConfetto = null;
                        handled = true;
                    }
                    break;
            }
        }

        return handled;
    }
}
